import {
  CanActivate,
  ExecutionContext,
  HttpException,
  Inject,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Request } from 'express';
import { EntityManager } from 'typeorm';
import { IS_PUBLIC_KEY } from './decorators/auth.decorator';
import { Role } from 'src/user/entities/role.enum';
@Injectable()
export class RolesGuard implements CanActivate {
  @Inject(Reflector)
  private reflector: Reflector;
  constructor(private readonly em: EntityManager) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request: Request = context.switchToHttp().getRequest();

    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) {
      // 💡 See this condition
      return true;
    }

    const requiredRoles = this.reflector.getAllAndOverride<string[]>(
      'require-roles',
      [context.getClass(), context.getHandler()],
    );

    if (!requiredRoles) {
      return true;
    }

    if (!request['user']) {
      throw new UnauthorizedException();
    }

    // 获取当前用户ID
    const userId = request['user'].userId;

    let user = null;
    try {
      user = await this.em.getRepository('User').findOneBy({ id: userId });
    } catch (error) {
      throw new HttpException(JSON.stringify(error), 500);
    }
    if (!user) {
      throw new UnauthorizedException('用户不存在');
    }

    // 单独处理超管角色
    if (user.isAdmin && requiredRoles.includes(Role.SUPER_ADMIN)) {
      return true;
    }

    if (user.isFrozen) {
      throw new HttpException('账号被冻结，请联系管理员', 403);
    }

    // 获取当前用户所在商户
    const tenantId = request.headers['x-tenant-id'];
    if (!tenantId) {
      throw new HttpException('抱歉，您当前还没有选择门店', 400);
    }

    // 获取当前用户在所在商户的角色
    let roles = null;
    try {
      roles = await this.em
        .getRepository('RoleEntity')
        .findBy({ userId, tenantId });
    } catch (error) {
      throw new HttpException(JSON.stringify(error), 500);
    }

    if (!roles || roles.length === 0) {
      throw new UnauthorizedException();
    }

    const role = roles[0].role;

    const found = requiredRoles.findIndex((item) => item === role) !== -1;

    if (!found) {
      throw new UnauthorizedException();
    }
    return true;
  }
}
